#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>

#include "../Utils/Utils.h"
#include "../Utils/BasicTypes.h"
#include "../LocalStack/LocalStack.h"

#include "sparse_matrix.h"

#include "LinearIO.h"

sparse_matrix_lst* ReadInMatrix(const char* fileName)
{
	int matrixSize;
	FILE* inpFile;
	sparse_matrix_lst* matrix;
	
	START();
	
	if (NULL == (inpFile = fopen(fileName, "r")))
		return NULL;
		
	SAFED(inpFile, FileCloser);
	Assert(fscanf(inpFile, "%d", &matrixSize) != 1);
	SAFED(matrix = allocate_sparse_matrix_lst(matrixSize), free_sparse_matrix_lst);
	Assert(ScanInMatrix(matrix, inpFile) == NULL);
	Assert(fclose(inpFile) == EOF);
	
	Delete(matrix);
	
	RETURN(matrix);
}

sparse_matrix_lst* ScanInMatrix(sparse_matrix_lst* inpMatrix, FILE* inpFile)
{
	cell_t** tempColPtr = NULL;
	cell_t *rowIter, *tempCell;
	int colCounter = 0, rowCounter = 0;
	elem input;

	START();
	
	tempColPtr = (cell_t**)NEW(sizeof(cell_t*) * inpMatrix->n);
	
	for (colCounter = 0; colCounter < inpMatrix->n; colCounter++)
		tempColPtr[colCounter] = NULL;
	
	for (rowCounter = 0; rowCounter < inpMatrix->n; rowCounter++)
	{
		rowIter = NULL;
		for (colCounter = 0; colCounter < inpMatrix->n; colCounter++)
		{
			Assert(fscanf(inpFile, "%lf", &input) != 1);
			
			if (input != 0)
			{
				SAFE(tempCell = InitCell(rowCounter, colCounter, input));
				if (rowIter == NULL)
					inpMatrix->rows[rowCounter] = tempCell;
				else
					rowIter->row_next = tempCell;
				
				rowIter = tempCell;
				
				if (tempColPtr[colCounter] == NULL)
					inpMatrix->cols[colCounter] = tempCell;
				else
					tempColPtr[colCounter]->col_next = tempCell;
				
				tempColPtr[colCounter] = tempCell;
			}
		}
	}
	
	Delete(tempColPtr);
	
	RETURN(inpMatrix);
}

bool ScanInVector(unsigned n, elem* vector)
{
	int l;
	
	for (l = 0; l < n; l++)
		if (scanf("%lf", vector + l) != 1)
			return FALSE;

	return TRUE;
}

bool PrintOutVector(unsigned n, const elem* vector)
{
	int l;
	for (l = 0; l < n; l++)
	{
		if(printf("%lf ", vector[l]) < 0)
			return FALSE;
	}
	return TRUE;
}

bool PrintOutZeros(int n)
{
	int l;
	for (l = 0; l < n; l++)
	{
		FAssert(printf(" %lf", 0.0) > 0);
	}
	
	return TRUE;
}

bool PrintOutMatrix(sparse_matrix_lst* matrix)
{
	int rowCounter = 0;
	int lastCol = 0;
	cell_t* colIter = NULL;
	
	FAssertM(printf("%d", matrix->n) < 0, "Error while printing matrix size.");
	
	for (rowCounter = 0; rowCounter < matrix->n; rowCounter++)
	{
		colIter = matrix->rows[rowCounter];
		lastCol = -1;
		
		while(colIter != NULL)
		{
			FAssert(PrintOutZeros(((colIter == NULL) ? matrix->n : colIter->colind) - lastCol - 1));
			FAssertM(printf(" %lf", colIter->value) >= 0, "Error while printing matrix value.");
			
			lastCol = colIter->colind;
			colIter = colIter->col_next;
		}
		
		FAssert(PrintOutZeros(matrix->n - lastCol - 1));
	}
	
	return TRUE;
}
